package com.robotic.udp;

import com.alibaba.fastjson2.JSONObject;
import com.jcraft.jsch.*;
import com.robotic.common.utils.StringUtils;
import com.robotic.kafka.KafkaProducerService;
import com.robotic.minio.MinioService;
import com.robotic.minio.RTSPFrameCaptureWithJavaCV;
import com.robotic.route.mapper.InspectionCalendarMapper;
import com.robotic.route.mapper.InspectionTaskMapper;
import com.robotic.tcp.RobotMonitor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/*
 * 批量遍历每个 JSON 文件，自动修改 config.toml，执行一次 player.sh。
 * 用 echo 2 方式给脚本管道输入自动选“导航模式2”（可根据实际情况调整）。
 * 远程所有输出直接打印在本地控制台。
 * 工具方法 execCommand 统一处理 SSH 执行与输出。
 */
@Component("executeNavigation")
@Slf4j
public class ExecuteNavigation {

    private final static String host = "10.110.7.219";
    private final static int port = 22;
    private final static String user = "ysc";
    private final static String password = "'"; // 请用实际密码
    private final static String remoteDir = "/home/ysc/jy_cog/system/data/";
    private final static String configPath = "/home/ysc/jy_cog/system/conf/player/config.toml";
    private final static String scriptPath = "/home/ysc/jy_cog/player/scripts/player.sh";

    public static boolean startPlayer = false;

    @Autowired
    private RTSPFrameCaptureWithJavaCV rtspFrameCaptureWithJavaCV;

    @Autowired
    private MinioService minioService;

    @Autowired
    private KafkaProducerService kafkaProducerService;

    @Autowired
    private InspectionTaskMapper inspectionTaskMapper;

    @Autowired
    public InspectionCalendarMapper inspectionCalendarMapper;

    public String pointName = null;

    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public Map<String, String> getFileContents() {
        Map<String, String> fileContentsMap = new HashMap<>();
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp sftpChannel = null;
        try {
            // 1. Establish SSH session
            session = jsch.getSession(user, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 2. Establish SFTP channel and list all JSON files
            Channel sftp = session.openChannel("sftp");
            sftp.connect();
            sftpChannel = (ChannelSftp) sftp;

            Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(remoteDir + "*.json");
            if (files.isEmpty()) {
                log.info("No JSON files found in the directory.");
                return fileContentsMap;
            }

            // 3. Iterate through files, read content, and parse JSON
            for (ChannelSftp.LsEntry entry : files) {
                String fileName = entry.getFilename();
                try (InputStream inputStream = sftpChannel.get(remoteDir + fileName)) {
                    StringBuilder content = new StringBuilder();
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        content.append(new String(buffer, 0, bytesRead));
                    }

                    String fileBaseName = fileName.replace(".json", "").split("_")[1];

                    // Put the filename and the parsed JSON content into the map
                    fileContentsMap.put(fileBaseName, content.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sftpChannel != null && sftpChannel.isConnected()) {
                sftpChannel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
        return fileContentsMap;
    }

    public List<String> getLines() {
        List<String> fileNames = new ArrayList<>();
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp sftpChannel = null;
        try {
            // 1. 建立 SSH 会话
            session = jsch.getSession(user, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 2. 建立 SFTP 通道，列出所有 json 文件
            Channel sftp = session.openChannel("sftp");
            sftp.connect();
            sftpChannel = (ChannelSftp) sftp;

            Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(remoteDir + "*.json");
            if (files.size() == 0) {
                log.info("目录下无 JSON 文件");
                return fileNames;
            }

            for (ChannelSftp.LsEntry entry : files) {
                String fileName = entry.getFilename().replace(".json", "");
                fileNames.add(fileName.split("_")[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sftpChannel != null && sftpChannel.isConnected()) sftpChannel.disconnect();
            if (session != null && session.isConnected()) session.disconnect();
        }
        return fileNames;
    }

    // 执行充电
    private void executeCharge() {

    }

    // 执行导航线路
    public void executePlayer(String fileAbsPath) {
        // 查询路线
       /* LambdaQueryWrapper<InspectionTaskVo> queryWrapper = Wrappers.lambdaQuery(InspectionTaskVo.class);
        queryWrapper.eq(InspectionTaskVo::getRouteCode, fileAbsPath);
        queryWrapper.last("limit 1");
        InspectionTaskVo inspectionTask = inspectionTaskMapper.selectOne(queryWrapper);
        String taskName = inspectionTask.getTaskName();
        Date now = DateUtils.getNowDate();*/

        startPlayer = true;
        RobotMonitor.xyList = new ArrayList<>();
        JSONObject lastBattery = UnifiedUDPReceiver.lastBattery;
        int batteryLevel = Integer.parseInt(String.valueOf(lastBattery.get("batteryData")));
        if (batteryLevel < 10) {
            fileAbsPath = "chongdian";
        }
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp sftpChannel = null;
        try {
            // 1. 建立 SSH 会话
            session = jsch.getSession(user, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 2. 建立 SFTP 通道，列出所有 json 文件
            Channel sftp = session.openChannel("sftp");
            sftp.connect();
            sftpChannel = (ChannelSftp) sftp;

            Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(remoteDir + "*.json");
            if (files.size() == 0) {
                log.info("目录下无 JSON 文件");
                return;
            }

            for (ChannelSftp.LsEntry entry : files) {
                String fileName = entry.getFilename();
                String jsonFilePath = remoteDir + fileName;
                if (jsonFilePath.contains(fileAbsPath)) {
                    log.info("\n==== 处理任务文件: " + jsonFilePath + " ====");
                    // 3. 用 SSH 修改 config.toml 的 points_path 字段
                    String sedCommand = "sed -i 's|^points_path = \".*\"|points_path = \"" + jsonFilePath + "\"|;s|^times = .*|times = 1|' " + configPath;
                    //String sedCommand = "sed -i 's|^points_path = \".*\"|points_path = \"" + jsonFilePath + "\"|' " + configPath;
                    log.info("执行配置修改命令: " + sedCommand);
                    execCommand(session, sedCommand, null, null);

                    // 4. 执行脚本 player.sh (假设用 echo 2 管道自动选模式)
                    String runScriptCommand = "echo 2 | bash " + scriptPath;
                    log.info("执行任务脚本: " + runScriptCommand);
                    execCommand(session, runScriptCommand, null, null);
                }
            }


            if (batteryLevel < 35) {
                executeCharge();
            }

           /* if (udpReceiver.lastRobotGaitState) {

            }*/

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sftpChannel != null && sftpChannel.isConnected()) sftpChannel.disconnect();
            if (session != null && session.isConnected()) session.disconnect();
            startPlayer = false;
            /*if (!fileAbsPath.contains("chongdian")) {
                // 创建一个新线程来异步执行任务状态的轮询，不影响主程序
                new Thread(() -> {
                    long startTime = System.currentTimeMillis();
                    long maxDuration = 20 * 60 * 1000; // 20分钟，单位为毫秒
                    Integer navStatus = -1; // 初始化状态，确保进入循环

                    log.info("开始轮询导航任务状态，最长持续20分钟...");

                    // 轮询任务状态，直到任务完成（navStatus = 0）或超时
                    while (navStatus != 0 && (System.currentTimeMillis() - startTime) < maxDuration) {
                        try {
                            // 每隔一秒获取一次导航任务状态
                            navStatus = navStatusQueryClient.getNavStatus();
                            log.info("当前导航任务状态: " + navStatus);
                            Thread.sleep(10000); // 暂停10秒
                        } catch (Exception e) {
                            System.err.println("获取导航状态时发生错误: " + e.getMessage());
                            // 出现错误时继续重试，或者根据需要跳出循环
                        }
                    }

                    // 检查循环终止条件
                    if (navStatus == 0) {
                        log.info("导航任务已完成，准备执行“趴下”指令。");
                    } else {
                        log.info("轮询超时（20分钟），任务可能仍在执行中。仍将执行“趴下”指令。");
                    }

                    // 任务执行完成或超时，使机器人趴下
                    try {
                        robotPoseTCPClient.executeLieDown();
                        log.info("已发送机器人“趴下”指令。");
                    } catch (Exception e) {
                        System.err.println("发送“趴下”指令时发生错误: " + e.getMessage());
                    }

                }).start(); // 启动线程
            }*/
        }
    }

    // 工具方法：在 session 上远程执行命令，并打印输出
    private void execCommand(Session session, String command, String taskName, Date now) throws Exception {
        ChannelExec execChannel = null;
        InputStream in = null;
        InputStream err = null;
        try {
            execChannel = (ChannelExec) session.openChannel("exec");
            execChannel.setCommand(command);
            execChannel.setErrStream(System.err);
            in = execChannel.getInputStream();
            err = execChannel.getErrStream();
            execChannel.connect();

            // 读取输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            String line;
            while ((line = reader.readLine()) != null) {

                String pointNumber = "";
                if (line.contains("目标点位")) {
                    log.info(line);
                    log.info("---------------------------");
                    pointNumber = extractTargetPointNumber(line);
                   /* if (StringUtils.isNotEmpty(pointNumber)) {
                        InspectionCalendar inspectionCalendar = new InspectionCalendar();
                        inspectionCalendar.setTaskName(taskName);
                        inspectionCalendar.setStatus("0");
                        inspectionCalendar.setExecuteTime(new Date());
                        inspectionCalendar.setInspectionTime(now);
                        inspectionCalendar.setPointCode(pointNumber);
                        inspectionCalendarMapper.insert(inspectionCalendar);
                    }*/
                    switch (pointNumber) {
                        case "9":
                        case "13":
                        case "14":
                        case "19":
                        case "21":
                            pointName = "电箱";
                            break;
                        case "10":
                        case "20":
                            pointName = "消防栓";
                            break;
                    }
                }
                log.info("pointNumber = {}, pointName = {}", pointNumber, pointName);
                if (StringUtils.isNotEmpty(pointName) && UnifiedUDPReceiver.lastRobotGaitState != null && UnifiedUDPReceiver.lastRobotGaitState != 4) {
                    MultipartFile multipartFile = rtspFrameCaptureWithJavaCV.captureFrameAsMultipartFile();
                    String fileUrl = minioService.uploadFile(multipartFile);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("type", "1");
                    jsonObject.put("workShop", "装配车间");
                    jsonObject.put("deviceName", "四足机器人");
                    jsonObject.put("pointName", pointName);
                    jsonObject.put("behaviorName", "杂物");
                    jsonObject.put("captureTime", System.currentTimeMillis());
                    jsonObject.put("backgroundPicUrl", fileUrl);
                    kafkaProducerService.sendMessage(jsonObject.toJSONString());
                    pointName = null;
                    log.info("============= {}", jsonObject.toJSONString());
                }
                log.info(line);
            }
            reader.close();

            // 读取错误流（可选）
            /*BufferedReader errReader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
            while ((line = errReader.readLine()) != null) {
                System.err.println(line);
            }
            errReader.close();*/

            int exitStatus = execChannel.getExitStatus();
            execChannel.disconnect();
            log.info("命令执行完毕，退出码: " + exitStatus);
        } finally {
            if (in != null) in.close();
            if (err != null) err.close();
            if (execChannel != null && execChannel.isConnected()) execChannel.disconnect();
        }
    }

    /**
     * 从包含特定格式的日志字符串中提取目标点位编号。
     *
     * @param logText 完整的日志文本块。
     * @return 如果找到，则返回提取到的数字；如果未找到，则返回-1或其他错误标识。
     */
    public static String extractTargetPointNumber(String logText) {
        // 1. 定义正则表达式，用于匹配“目标点位：”后面的一个或多个数字。
        //    \\d+ 匹配一个或多个数字。
        //    ()   表示一个捕获组，方便我们只提取括号内的内容（也就是数字）。
        String regex = "目标点位：(\\d+)";

        // 2. 编译正则表达式
        Pattern pattern = Pattern.compile(regex);

        // 3. 在输入的日志文本中创建匹配器
        Matcher matcher = pattern.matcher(logText);

        // 4. 查找匹配项
        if (matcher.find()) {
            // 如果找到匹配项，matcher.group(1) 会返回第一个捕获组的内容
            // 即 "(\\d+)" 匹配到的数字字符串。

            return matcher.group(1);
        }
        return "0";
    }

}

